表单工具函数 useForm
概述
本节封装 useForm 工具函数,解决 schema 嵌套结构导致的数据映射问题。useForm 是表单组件的统一入口,负责管理表单数据模型、校验状态和表单方法。
问题分析:Schema 嵌套与数据结构不一致
问题表现
schema 中的嵌套结构导致生成的 model 对象与预期不符:
// Schema 定义
const schema = [
{
field: 'group1',
children: [
{ field: 'data1', type: 'input', value: '' },
{ field: 'data2', type: 'input', value: '' },
],
},
]
// 期望的 model 结构
{ data1: '', data2: '' }
// 实际生成的结构(嵌套在 group1 下)
{ group1: { data1: '', data2: '' } }
typescript
方案对比
| 方案 | 实现方式 | 优点 | 缺点 |
|---|---|---|---|
| Schema 扁平化 | 添加 level 字段 | 结构简单 | 书写复杂嵌套时易混淆 |
| 转换函数 | 嵌套写 + 运行时展平 | Schema 可读性好 | 需额外转换逻辑 |
| useForm 封装 | 统一入口管理 | 使用简洁,封装复杂性 | 需额外封装工作 |
useForm 实现
基础结构
// composables/useForm.ts
import { reactive, computed, type Ref } from 'vue'
interface FormSchema {
field: string
type: string
value?: any
children?: FormSchema[]
rules?: any[]
}
interface UseFormReturn {
model: Record<string, any>
formValue: computed<Record<string, any>>
setForm: (schema: FormSchema[]) => void
validate: () => Promise<boolean>
resetForm: () => void
}
export function useForm(schema: FormSchema[]): UseFormReturn {
const model = reactive<Record<string, any>>({})
// 扁平化提取表单值
function setForm(schemaList: FormSchema[]) {
schemaList.forEach(item => {
if (item.children) {
item.children.forEach(child => {
model[child.field] = child.value ?? ''
})
} else {
model[item.field] = item.value ?? ''
}
})
}
// 表单值的计算属性
const formValue = computed(() => ({ ...model }))
// 校验方法
async function validate(): Promise<boolean> {
// 校验逻辑
return true
}
// 重置表单
function resetForm() {
setForm(schema)
}
// 初始化
setForm(schema)
return {
model,
formValue,
setForm,
validate,
resetForm,
}
}
typescript
使用方式
import { useForm } from '@el-admin/components'
const schema = [
{ field: 'username', type: 'input', value: '' },
{ field: 'resources', type: 'checkbox', value: [] },
{
field: 'group1',
children: [
{ field: 'data1', type: 'input', value: '' },
{ field: 'data2', type: 'input', value: '' },
],
},
]
const { model, formValue, validate } = useForm(schema)
typescript
useForm 与 VForm 的配合
<template>
<VForm :schema="schema" :model="model" />
</template>
<script setup lang="ts">
const { model, formValue, validate } = useForm(schema)
</script>
vue
useForm(schema)
│
├── model ──────────> VForm v-model
│ │
│ 用户输入 ←───────────┘
│
├── formValue ────> 外部读取表单值
│
├── validate() ───> 触发表单校验
│
└── resetForm() ──> 重置为初始值
text
关键要点
useForm是表单组件的推荐使用方式,封装了数据模型的初始化和管理- Schema 扁平化虽简单但增加了书写复杂度,
useForm内部处理嵌套,对外提供扁平的 model setForm方法负责从 schema 提取所有字段并初始化值- 后续可扩展:异步校验、联动字段、动态 schema 更新
↑